package org.kits.controller;

import com.alibaba.fastjson.JSONObject;
import org.kits.service.RedisDemoService;
import org.kits.service.RedisScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author SKyOne
 * @create 2020-03-08 18:49
 */
@RestController
@RequestMapping("/redis")
public class RedisDemoController {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    RedisDemoService redisDemoService;

    @Autowired
    RedisScan redisScan;

    /**
     * 限流算法除了控制流量，限流还有一个应用目的是用于控制用户行为，避免垃圾请求
     * 这个限流需求中存在一个滑动时间窗口，想想 zset 数据结构的 score 值，是不是可以
     * 通过 score 来圈出这个时间窗口来。而且我们只需要保留这个时间窗口，窗口之外的数据都
     * 可以砍掉。那这个 zset 的 value 填什么比较合适呢？它只需要保证唯一性即可，用 uuid 会
     * 比较浪费空间，那就改用毫秒时间戳吧。
     */
    @GetMapping("/ratelimite")
    public void rateLimter(){
        for (int i = 0; i <20; i++) {
            redisDemoService.isActionAllowed("test","reply",60,5);
        }
    }

    @GetMapping("/pipe")
    public String testPipe() {
        List<Object> resultList = redisTemplate.executePipelined(new RedisCallback<Object>() {

            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
//                2.connection 打开管道
                connection.openPipeline();

//                3.connection 给本次管道内添加 要一次性执行的多条命令

//                3.1 一个set操作
                byte[] key1 = "mykey1".getBytes();
                byte[] value1 = "字符串value".getBytes();
                connection.set(key1, value1);

//                3.2一个批量mset操作
                Map<byte[], byte[]> tuple = new HashMap<>();
                tuple.put("m_mykey1".getBytes(), "m_value1".getBytes());
                tuple.put("m_mykey2".getBytes(), "m_value2".getBytes());
                tuple.put("m_mykey3".getBytes(), "m_value3".getBytes());
                connection.mSet(tuple);

//                 3.3一个get操作
                 connection.get("m_mykey2".getBytes());

//                4.关闭管道 不需要close 否则拿不到返回值
//                connection.closePipeline();

//                这里一定要返回null，最终pipeline的执行结果，才会返回给最外层
                return null;
            }
        });


//        5.最后对redis pipeline管道操作返回结果进行判断和业务补偿
        for (Object str : resultList) {
            System.out.println(String.valueOf(str));
        }

        return JSONObject.toJSONString(resultList);
    }

    @GetMapping("/addval")
    public void addValue(){
        redisScan.addVal();
    }
}
